home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume19 / fbm / part07 < prev    next >
Encoding:
Internet Message Format  |  1989-06-08  |  54.7 KB

  1. Subject:  v19i053:  FBM, image manipulation library, Part07/08
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Michael.Mauldin@NL.CS.CMU.EDU
  7. Posting-number: Volume 19, Issue 53
  8. Archive-name: fbm/part07
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 7 (of 8)."
  17. # Contents:  fbham.c flgifr.c fliff.c
  18. # Wrapped by rsalz@fig.bbn.com on Fri Jun  9 08:38:29 1989
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'fbham.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'fbham.c'\"
  22. else
  23. echo shar: Extracting \"'fbham.c'\" \(14765 characters\)
  24. sed "s/^X//" >'fbham.c' <<'END_OF_FILE'
  25. X/*****************************************************************
  26. X * fbham.c: FBM Library 0.94 (Beta test) 20-May-89  Michael Mauldin
  27. X *
  28. X * fbham.c: Write a 24bit RGB file as an Amiga HAM IFF file
  29. X *
  30. X * USAGE
  31. X *     % fbham < image1 > image2
  32. X *
  33. X * EDITLOG
  34. X *    LastEditDate = Sat May 20 19:15:08 1989 - Michael Mauldin
  35. X *    LastFileName = /usr2/mlm/src/misc/fbm/fbham.c
  36. X *
  37. X * HISTORY
  38. X * 20-May-89  Michael Mauldin (mlm) at Carnegie Mellon University
  39. X *    Beta release (version 0.94) mlm@cs.cmu.edu
  40. X *
  41. X * 20-Apr-89  C. Harald Koch (chk) at DCIEM Toronto.
  42. X *     Created.  chk@ben.dciem.dnd.ca
  43. X *
  44. X *================================================================
  45. X * based on ray2.c from DBW_Render, Copyright 1987 David B. Wecker
  46. X *
  47. X * From: chk@dretor.dciem.dnd.ca (C. Harald Koch)
  48. X * Subject: fbham.c - convert a 24bit FBM file to an IFF file using HAM mode
  49. X * To: Michael.Mauldin@nl.cs.cmu.edu (Michael Maudlin)
  50. X * Date: Mon, 1 May 89 17:21:16 EDT
  51. X * X-Mailer: ELM [version 2.2 PL0]
  52. X * 
  53. X * This is the source to my program to convert from a 24bit FBM file to Amiga
  54. X * HAM mode. It is based on Dave Wecker's RAY2 program, which converts the
  55. X * output of his raytracer to HAM mode. His code uses the Amiga graphics
  56. X * library to plot the pixels in a framebuffer for encoding; this version will
  57. X * run standalone.
  58. X * 
  59. X * There may be bugs, although it works well for me here. It is probably not in
  60. X * the format you want for FBM source; Please go ahead and modify it. There is
  61. X * probably room for some command line options for various things (such as the
  62. X * verbose output, run length encoding, etc) which I haven't needed and so
  63. X * haven't added.
  64. X * 
  65. X * I will send you the IRIS programs when I get them. Enjoy!
  66. X *    -chk
  67. X *****************************************************************/
  68. X
  69. X#include <stdio.h>
  70. X#include <math.h>
  71. X#include "fbm.h"
  72. X
  73. X# define USAGE "Usage: fbham < image > image"
  74. X
  75. X#ifndef lint
  76. Xstatic char    *fbmid = 
  77. X"$FBM fbham.c <0.93> 03-May-89  (C) 1989 by C. Harald Koch$";
  78. X#endif
  79. X
  80. X#define DEPTH        6        /* max depth of Amiga HAM image */
  81. X
  82. X#define BMHDsize    20L        /* chunk sizes */
  83. X#define CMAPsize    96L
  84. X#define CAMGsize    4L
  85. X#define BODYsize    ((long)(16000L))
  86. X#define FORMsize    (BODYsize+CAMGsize+CMAPsize+BMHDsize+36L)
  87. X
  88. Xunsigned char *planes[DEPTH];    /* bitplane pointers */
  89. X
  90. Xstatic int      comp = 1;    /* compress image? */
  91. Xstatic int      depth = DEPTH;    /* depth of image being created */
  92. Xstatic int      colors = 16;    /* number of colors in color lookup table */
  93. Xstatic int      colorstats[4096][2];    /* color usage statistics */
  94. Xstatic int    row_size;    /* number of bytes in IFF row of data */
  95. X
  96. X/* temp variables for writing IFF file */
  97. Xchar            str[40];
  98. Xlong            lng, pos1, pos2;
  99. Xshort           wrd;
  100. Xunsigned char   byt;
  101. Xunsigned char  *dest, destbuf[BUFSIZ];
  102. X
  103. X
  104. Xmain(argc, argv)
  105. Xchar           *argv[];
  106. X{
  107. X    FBM             input;
  108. X
  109. X    /* Clear the memory pointers so alloc_fbm won't be confused */
  110. X    input.cm = input.bm = (unsigned char *) NULL;
  111. X
  112. X    /* Read the image and rotate it */
  113. X    if (!read_bitmap(&input, argc > 0 ? argv[1] : (char *) NULL))
  114. X    {
  115. X    exit(1);
  116. X    }
  117. X
  118. X    /* slight sanity checks. could be better. */
  119. X    if (input.hdr.physbits != 8 || input.hdr.planes != 3) {
  120. X    fprintf(stderr, "input file must be 24 bit RGB data\n");
  121. X    exit(1);
  122. X    }
  123. X
  124. X    /* convert to HAM */
  125. X    if (!fbm2ham(&input, stdout)) {
  126. X    exit(1);
  127. X    }
  128. X
  129. X    exit(0);
  130. X}
  131. X
  132. X
  133. X/************************ run length encoding from Amiga RKM *****************/
  134. X#define DUMP        0   /* list of different bytes */
  135. X#define RUN        1   /* single run of bytes */
  136. X#define MinRun        3   /* shortest allowed run */
  137. X#define MaxRun        128 /* longest run (length is signed char) */
  138. X#define    MaxDat        128 /* longest block of unencoded data */
  139. X#define GetByte()    (*source++)
  140. X#define PutByte(c)    { *dest++ = (c); ++PutSize; }
  141. X#define OutDump(nn)    dest = PutDump(dest,nn);
  142. X#define OutRun(nn,cc)    dest = PutRun(dest,nn,cc);
  143. X
  144. Xint             PutSize;
  145. Xchar            buf[256];
  146. X
  147. Xunsigned char  *
  148. XPutDump(dest, nn)
  149. Xunsigned char  *dest;
  150. Xint             nn;
  151. X{
  152. X    int             i;
  153. X
  154. X    PutByte(nn - 1);
  155. X    for (i = 0; i < nn; i++)
  156. X    PutByte(buf[i]);
  157. X    return (dest);
  158. X}
  159. X
  160. Xunsigned char  *
  161. XPutRun(dest, nn, cc)
  162. Xunsigned char  *dest;
  163. Xint             nn, cc;
  164. X{
  165. X    PutByte(-(nn - 1));
  166. X    PutByte(cc);
  167. X    return (dest);
  168. X}
  169. X
  170. X/* PackRow - pack a row of data using Amiga IFF RLE */
  171. Xint 
  172. XPackRow(pSource, pDest, RowSize)
  173. Xunsigned char **pSource, **pDest;
  174. Xint             RowSize;
  175. X{
  176. X    unsigned char  *source, *dest;
  177. X    char            c, lastc = '\000';
  178. X    int             mode = DUMP, nbuf = 0,    /* number of chars in buf */
  179. X                    rstart = 0;    /* buf index current run starts */
  180. X
  181. X    source = *pSource;
  182. X    dest = *pDest;
  183. X
  184. X    PutSize = 0;
  185. X    buf[0] = lastc = c = GetByte();
  186. X    nbuf = 1;
  187. X    RowSize--;
  188. X
  189. X    for (; RowSize; --RowSize) {
  190. X    buf[nbuf++] = c = GetByte();
  191. X
  192. X    switch (mode) {
  193. X    case DUMP:
  194. X        if (nbuf > MaxDat) {
  195. X        OutDump(nbuf - 1);
  196. X        buf[0] = c;
  197. X        nbuf = 1;
  198. X        rstart = 0;
  199. X        break;
  200. X        }
  201. X        if (c == lastc) {
  202. X        if (nbuf - rstart >= MinRun) {
  203. X            if (rstart > 0)
  204. X            OutDump(rstart);
  205. X            mode = RUN;
  206. X        }
  207. X        else if (rstart == 0)
  208. X            mode = RUN;
  209. X        }
  210. X        else
  211. X        rstart = nbuf - 1;
  212. X        break;
  213. X
  214. X    case RUN:
  215. X        if ((c != lastc) || (nbuf - rstart > MaxRun)) {
  216. X        OutRun((nbuf - 1) - rstart, lastc);
  217. X        buf[0] = c;
  218. X        nbuf = 1;
  219. X        rstart = 0;
  220. X        mode = DUMP;
  221. X        }
  222. X        break;
  223. X    }
  224. X    lastc = c;
  225. X    }
  226. X    switch (mode) {
  227. X    case DUMP:
  228. X    OutDump(nbuf);
  229. X    break;
  230. X    case RUN:
  231. X    OutRun(nbuf - rstart, lastc);
  232. X    break;
  233. X    }
  234. X
  235. X    *pSource = source;
  236. X    *pDest = dest;
  237. X
  238. X    return (PutSize);
  239. X}
  240. X/******************* end of RKM RL encoding routines **********************/
  241. X
  242. X
  243. X/* build_histogram - count frequency of 12bit colors in an FBM image */
  244. Xbuild_histogram(image)
  245. XFBM *image;
  246. X{
  247. X    int i, j, t0, t1, gap, val, used;
  248. X    unsigned char *rp, *gp, *bp;
  249. X    int diff;
  250. X
  251. X    /* initialize color statistics. */
  252. X    for (i = 0; i < 4096; i++) {
  253. X    colorstats[i][0] = i;
  254. X    colorstats[i][1] = 0;
  255. X    }
  256. X
  257. X    /* obtain pointers to the beginning of each plane (Red, Green, Blue) */
  258. X    rp = image->bm;
  259. X    gp = rp + image->hdr.plnlen;
  260. X    bp = gp + image->hdr.plnlen;
  261. X
  262. X    /* count the number of occurences of each color in the image */
  263. X    for (i = 0 ; i < image->hdr.plnlen ; i++) {
  264. X    val = ((*rp++ & 0xf0) << 4) + (*gp++ & 0xf0) + ((*bp++ & 0xf0) >> 4);
  265. X    val %= 4096;
  266. X    if (colorstats[val][1] < 32767) {
  267. X        colorstats[val][1]++;
  268. X    }
  269. X    }
  270. X
  271. X    /* sort the color stats in order of decreasing usage */
  272. X    for (gap = 2048; gap > 0; gap /= 2) {
  273. X    for (i = gap; i < 4096; i++) {
  274. X        for (j = i - gap; j >= 0 &&
  275. X            colorstats[j][1] < colorstats[j + gap][1]; j -= gap) {
  276. X        t0 = colorstats[j][0];
  277. X        t1 = colorstats[j][1];
  278. X        colorstats[j][0] = colorstats[j + gap][0];
  279. X        colorstats[j][1] = colorstats[j + gap][1];
  280. X        colorstats[j + gap][0] = t0;
  281. X        colorstats[j + gap][1] = t1;
  282. X        }
  283. X    }
  284. X    }
  285. X
  286. X    /* count the number of colors actually used in the image */
  287. X    for (used = 0; used < 4096 && colorstats[used][1] > 0; used++);
  288. X    fprintf(stderr, "Used %d colors out of a possible 4096\n", used);
  289. X}
  290. X
  291. X/*-
  292. X * plot_pixel - plot a color in an Amiga style bitmap (one plane per bit)
  293. X *
  294. X * Description:
  295. X *    A somewhat optimized routine to set/reset one bit in each plane
  296. X *    at the specified (x,y) coordinates. plane i gets the bit in
  297. X *    position i of color. a replacement for the Amiga WritePixel call.
  298. X-*/
  299. Xplot_pixel(planes, x, y, color)
  300. Xunsigned char *planes[];
  301. Xint x, y;
  302. Xregister int color;
  303. X{
  304. X    register int bit;
  305. X    register unsigned char shifted_bit = 1 << (7-(x%8));
  306. X    register int array_offset = y * row_size + x/8;
  307. X    register int i;
  308. X
  309. X    for (i = 0; color && i < depth; i++) {
  310. X    bit = color & 1;
  311. X    color >>= 1;
  312. X
  313. X    if (bit)    *(planes[i] + array_offset) |= shifted_bit;
  314. X    }
  315. X}
  316. X
  317. X
  318. X/*-
  319. X * fbm2ham - write an FBM image in HAM IFF format on the given file pointer.
  320. X *
  321. X-*/
  322. Xfbm2ham(image, ofil)
  323. XFBM *image;
  324. XFILE *ofil;
  325. X{
  326. X    int             i, j, k, gap, t0, t1, prgb, crgb, cpix, ppix, maxdis, used;
  327. X    int            c1, c2, diff;
  328. X    unsigned char *rp, *gp, *bp;
  329. X
  330. X    fprintf(stderr, "Building a color histogram:\n");
  331. X    build_histogram(image);
  332. X
  333. X    /* convert the image to an Amiga HAM bitplane based image */
  334. X    cpix = 0;
  335. X    crgb = colorstats[0][1];
  336. X
  337. X    rp = image->bm;
  338. X    gp = rp + image->hdr.plnlen;
  339. X    bp = gp + image->hdr.plnlen;
  340. X
  341. X    row_size = ((image->hdr.cols + 15) / 16) * 2;
  342. X    diff = image->hdr.rowlen - image->hdr.cols;
  343. X
  344. X    for (i = 0; i < depth ; i++) {
  345. X    planes[i] = (unsigned char *)malloc(row_size * image->hdr.rows);
  346. X    }
  347. X
  348. X    for (i = 0; i < image->hdr.rows; i ++) {
  349. X    /* verbose output because this program is slow even on a Sun */
  350. X    if (i%50 == 0) { fprintf(stderr, "...%d", i); fflush(stderr); }
  351. X
  352. X    /* step through current row, converting FBM pixel to nearest equivalent
  353. X     * HAM pixel */
  354. X    for (j = 0; j < image->hdr.cols; j++) {
  355. X        prgb = crgb;
  356. X        crgb = ((*rp++ & 0xf0) << 4) + (*gp++ & 0xf0) + ((*bp++ & 0xf0) >> 4);
  357. X        crgb %= 4096;
  358. X        ppix = cpix;
  359. X
  360. X        /* start of scan line is ALWAYS an absolute color */
  361. X        if (j == 0)
  362. X        cpix = getcolor(ppix, &crgb, -1);
  363. X        else
  364. X        cpix = getcolor(ppix, &crgb, prgb);
  365. X
  366. X        /* plot the computed pixel */
  367. X        plot_pixel(planes, j, i, cpix);
  368. X    }
  369. X    rp += diff;
  370. X    gp += diff;
  371. X    bp += diff;
  372. X    }
  373. X    fprintf(stderr, "\n");
  374. X
  375. X    /* Now we write the planes[] array we just created in ILBM format */
  376. X    sprintf(str, "FORM");
  377. X    fwrite(str, 1, 4, ofil);
  378. X    pos1 = ftell(ofil);
  379. X    lng = FORMsize;
  380. X    fwrite(&lng, 4, 1, ofil);
  381. X    sprintf(str, "ILBM");
  382. X    fwrite(str, 1, 4, ofil);
  383. X
  384. X    sprintf(str, "BMHD");
  385. X    fwrite(str, 1, 4, ofil);
  386. X    lng = BMHDsize;
  387. X    fwrite(&lng, 4, 1, ofil);
  388. X    wrd = image->hdr.cols;
  389. X    fwrite(&wrd, 2, 1, ofil);    /* width */
  390. X    wrd = image->hdr.rows;
  391. X    fwrite(&wrd, 2, 1, ofil);    /* height */
  392. X    wrd = 0;
  393. X    fwrite(&wrd, 2, 1, ofil);    /* top */
  394. X    wrd = 0;
  395. X    fwrite(&wrd, 2, 1, ofil);    /* left */
  396. X    byt = depth;
  397. X    fwrite(&byt, 1, 1, ofil);    /* Depth */
  398. X    byt = 0;
  399. X    fwrite(&byt, 1, 1, ofil);    /* mask */
  400. X    byt = comp;
  401. X    fwrite(&byt, 1, 1, ofil);    /* compress */
  402. X    byt = 0;
  403. X    fwrite(&byt, 1, 1, ofil);    /* pad */
  404. X    wrd = 0;
  405. X    fwrite(&wrd, 2, 1, ofil);    /* transparency */
  406. X    byt = 10;
  407. X    fwrite(&byt, 1, 1, ofil);    /* aspect x */
  408. X    byt = 11;
  409. X    fwrite(&byt, 1, 1, ofil);    /* aspect y */
  410. X    wrd = image->hdr.cols;
  411. X    fwrite(&wrd, 2, 1, ofil);    /* page width */
  412. X    wrd = image->hdr.rows;
  413. X    fwrite(&wrd, 2, 1, ofil);    /* page height */
  414. X
  415. X    /* CAMG chunk for displaying files on the Amiga. should include at least
  416. X     * the HAM flag; I also add lace if the picture is large enough. Perhaps
  417. X     * this should be an option. -CHK */
  418. X    sprintf(str, "CAMG");
  419. X    fwrite(str, 1, 4, ofil);
  420. X    lng = CAMGsize;
  421. X    fwrite(&lng, 4, 1, ofil);
  422. X    if (image->hdr.rows > 200)
  423. X    lng = 0x804L;        /* HAM | LACE */
  424. X    else
  425. X    lng = 0x800L;        /* HAM */
  426. X    fwrite(&lng, 4, 1, ofil);
  427. X
  428. X    /* write out the color lookup table */
  429. X    sprintf(str, "CMAP");
  430. X    fwrite(str, 1, 4, ofil);
  431. X    lng = CMAPsize;
  432. X    fwrite(&lng, 4, 1, ofil);
  433. X    for (i = 0; i < 32; i++) {
  434. X    str[0] = (colorstats[i][0] >> 4) & 0xF0;
  435. X    str[1] = (colorstats[i][0]) & 0xF0;
  436. X    str[2] = (colorstats[i][0] << 4) & 0xF0;
  437. X    fwrite(str, 1, 3, ofil);
  438. X    }
  439. X
  440. X    sprintf(str, "BODY");
  441. X    fwrite(str, 1, 4, ofil);
  442. X    pos2 = ftell(ofil);
  443. X    lng = BODYsize;
  444. X    fwrite(&lng, 4, 1, ofil);
  445. X
  446. X    lng = 0L;
  447. X
  448. X    for (i = 0; i < image->hdr.rows; i ++) {
  449. X    for (j = 0; j < depth; j++) {
  450. X        if (comp) {
  451. X        dest = destbuf;
  452. X        wrd = PackRow(&planes[j], &dest, row_size);
  453. X        lng += (long) wrd;
  454. X        fwrite(destbuf, 1, wrd, ofil);
  455. X        }
  456. X        else {
  457. X        fwrite(planes[j], 1, row_size, ofil);
  458. X        planes[j] += row_size;
  459. X        }
  460. X    }
  461. X    }
  462. X    if (comp) {
  463. X    fseek(ofil, (long) pos2, 0);
  464. X    fwrite(&lng, 4, 1, ofil);
  465. X    lng -= BODYsize;
  466. X    lng += FORMsize;
  467. X    fseek(ofil, (long) pos1, 0);
  468. X    fwrite(&lng, 4, 1, ofil);
  469. X    }
  470. X
  471. X    return 1;
  472. X}
  473. X
  474. X/* get the next encoding for a pixel, based on the previous pixel and the
  475. X * current 12 bit RGB value */
  476. X
  477. X#define BPP        4        /* Bits per pixel */
  478. X#define MAXGRAY        (1 << BPP)
  479. X#define    ABS(x)        ((x) < 0 ? -(x) : (x))
  480. X
  481. X/*-
  482. X *    first, check to see if pixel is the same color. if so, return
  483. X *    check if only one of R, G, B have changed. if so, return new pixel.
  484. X *    find closest entry in colormap. if exact match, return it.
  485. X *    modify one of R, G, B (whichever difference is largest)
  486. X *    compare previous calculation to best match in color table. return
  487. X *        whichever is a better match.
  488. X-*/
  489. Xgetcolor(ppix, crgb, prgb)
  490. Xint             ppix, *crgb, prgb;
  491. X{
  492. X    int             i, j, val, cr, cg, cb, pr, pg, pb, nr, ng, nb, best, dist, nrgb;
  493. X
  494. X    /* if same color, then do a NOOP (same as previous pixel) */
  495. X    if (*crgb == prgb)
  496. X    return (ppix);
  497. X
  498. X    /* set up for comparisons */
  499. X    cb = *crgb & (MAXGRAY - 1);
  500. X    cg = (*crgb >> BPP) & (MAXGRAY - 1);
  501. X    cr = (*crgb >> (BPP * 2)) & (MAXGRAY - 1);
  502. X
  503. X    pb = prgb & (MAXGRAY - 1);
  504. X    pg = (prgb >> BPP) & (MAXGRAY - 1);
  505. X    pr = (prgb >> (BPP * 2)) & (MAXGRAY - 1);
  506. X
  507. X    /* see if only one plane changed, if so, use HAM encoding */
  508. X    if (prgb != -1) {
  509. X    if (pr == cr && pg == cg)
  510. X        return (cb + 0x10);
  511. X    if (pr == cr && pb == cb)
  512. X        return (cg + 0x30);
  513. X    if (pg == cg && pb == cb)
  514. X        return (cr + 0x20);
  515. X    }
  516. X
  517. X    /* else look for an exact match in the color table (or minimal distance) */
  518. X    for (i = 0; i < colors; i++) {
  519. X    if (colorstats[i][0] == *crgb)
  520. X        return (i);
  521. X    if (i == 0) {
  522. X        best = 0;
  523. X        dist = distance(colorstats[i][0], *crgb);
  524. X    }
  525. X    else if ((j = distance(colorstats[i][0], *crgb)) < dist) {
  526. X        best = i;
  527. X        dist = j;
  528. X    }
  529. X    }
  530. X
  531. X    /* do a forced absolute */
  532. X    if (prgb == -1) {
  533. X    *crgb = colorstats[best][0];
  534. X    return (best);
  535. X    }
  536. X
  537. X    /* find which color is off the most from previous */
  538. X    i = 0;
  539. X    val = ABS(cr - pr);
  540. X    if (ABS(cg - pg) > val) {
  541. X    i = 1;
  542. X    val = ABS(cg - pg);
  543. X    }
  544. X    if (ABS(cb - pb) > val) {
  545. X    i = 2;
  546. X    val = ABS(cb - pb);
  547. X    }
  548. X
  549. X    nr = pr;
  550. X    ng = pg;
  551. X    nb = pb;
  552. X    switch (i) {
  553. X    case 0:
  554. X    nr = cr;
  555. X    val = nr + 0x20;
  556. X    break;
  557. X    case 1:
  558. X    ng = cg;
  559. X    val = ng + 0x30;
  560. X    break;
  561. X    case 2:
  562. X    nb = cb;
  563. X    val = nb + 0x10;
  564. X    break;
  565. X    }
  566. X    nrgb = (nr << (2 * BPP)) + (ng << BPP) + nb;
  567. X
  568. X    /* now pick the best */
  569. X    if (distance(nrgb, *crgb) < dist) {
  570. X
  571. X    /* do a best relative */
  572. X    *crgb = nrgb;
  573. X    return (val);
  574. X    }
  575. X
  576. X    /* do a best absolute */
  577. X    *crgb = colorstats[best][0];
  578. X    return (best);
  579. X}
  580. X
  581. X/* calculate distance between two colors in 3D space */
  582. Xdistance(argb, brgb)
  583. X{
  584. X    int             b, g, r;
  585. X
  586. X    /* set up for comparisons */
  587. X    b = argb & (MAXGRAY - 1);
  588. X    g = (argb >> BPP) & (MAXGRAY - 1);
  589. X    r = (argb >> (BPP * 2)) & (MAXGRAY - 1);
  590. X
  591. X    b -= brgb & (MAXGRAY - 1);
  592. X    g -= (brgb >> BPP) & (MAXGRAY - 1);
  593. X    r -= (brgb >> (BPP * 2)) & (MAXGRAY - 1);
  594. X
  595. X    return (r * r + g * g + b * b);
  596. X}
  597. END_OF_FILE
  598. if test 14765 -ne `wc -c <'fbham.c'`; then
  599.     echo shar: \"'fbham.c'\" unpacked with wrong size!
  600. fi
  601. # end of 'fbham.c'
  602. fi
  603. if test -f 'flgifr.c' -a "${1}" != "-c" ; then 
  604.   echo shar: Will not clobber existing file \"'flgifr.c'\"
  605. else
  606. echo shar: Extracting \"'flgifr.c'\" \(13672 characters\)
  607. sed "s/^X//" >'flgifr.c' <<'END_OF_FILE'
  608. X/*****************************************************************
  609. X * flgifr.c: FBM Library 0.91 (Beta test) 26-Apr-89  Michael Mauldin
  610. X *
  611. X * Copyright (C) 1989 by Michael Mauldin.  Permission is granted to
  612. X * use this file in whole or in part provided that you do not sell it
  613. X * for profit and that this copyright notice is retained unchanged.
  614. X *
  615. X * Derived from 'giftorle', written by David Koblas
  616. X *
  617. X * +------------------------------------------------------------------+ 
  618. X * | Copyright 1989, David Koblas.                                    | 
  619. X * |   You may copy this file in whole or in part as long as you      | 
  620. X * |   don't try to make money off it, or pretend that you wrote it.  | 
  621. X * +------------------------------------------------------------------+ 
  622. X *
  623. X * flgifr.c:
  624. X *
  625. X * CONTENTS
  626. X *    read_gif (image, stream, mstr, mlen)
  627. X *
  628. X * HISTORY
  629. X * 26-Apr-89  Michael Mauldin (mlm) at Carnegie Mellon University
  630. X *    Beta release (version 0.91) mlm@cs.cmu.edu
  631. X *
  632. X * 19-Feb-89  Michael Mauldin (mlm) at Carnegie Mellon University
  633. X *    Changed name to flgifr from flgif (since there is now an flgifw)
  634. X *
  635. X * 13-Feb-89  Michael Mauldin (mlm) at Carnegie Mellon University
  636. X *    Modified from gif2rle program Copyright 1989 by David Koblas.
  637. X *    Converted to produce FBM image format in memory.
  638. X *
  639. X *
  640. X *****************************************************************/
  641. X
  642. X# include <stdio.h>
  643. X# include "fbm.h"
  644. X
  645. X#define MAXCOLORMAPSIZE         256
  646. X
  647. X#define TRUE    1
  648. X#define FALSE   0
  649. X#define BAD     0
  650. X#define OK      1
  651. X
  652. X#define MAX_LWZ_BITS            12
  653. X
  654. X#define ReadOK(file,buffer,len) (fread(buffer,len,1,file)!=0)
  655. X#define EasyFail(str,status)    while(1){fprintf(stderr,str);return(status);}
  656. X#define HardFail(str,status)    while(1){fprintf(stderr,str);exit  (status);}
  657. X
  658. X#define LM_to_uint(a,b)                 (((b)<<8)|(a))
  659. X
  660. X#ifndef lint
  661. Xstatic char *fbmid =
  662. X    "$FBM flgifr.c <0.91> 26-Apr-89  (C) 1989 by Michael Mauldin$";
  663. X#endif
  664. X
  665. Xread_gif (image, fd, mstr, mlen)
  666. XFBM *image;
  667. XFILE *fd;
  668. Xchar *mstr;
  669. Xint mlen;
  670. X{
  671. X  unsigned char   buf[16];
  672. X  unsigned char   c;
  673. X  int             use_global_colormap;
  674. X  int             bit_pixel;
  675. X  int             count = 0;
  676. X  int             rows, cols, rowlen, depth, colors;
  677. X
  678. X  /* Read magic number 'GIF87a' */
  679. X  buf[0] = NEXTMCH (fd, mstr, mlen) & 0xff;
  680. X  buf[1] = NEXTMCH (fd, mstr, mlen) & 0xff;
  681. X  buf[2] = NEXTMCH (fd, mstr, mlen) & 0xff;
  682. X  buf[3] = NEXTMCH (fd, mstr, mlen) & 0xff;
  683. X  buf[4] = NEXTMCH (fd, mstr, mlen) & 0xff;
  684. X  buf[5] = NEXTMCH (fd, mstr, mlen) & 0xff;
  685. X  buf[6] = 0;
  686. X
  687. X  if (strcmp (buf, GIF_MAGIC) != 0)
  688. X    EasyFail("bad magic number (version mismatch?)\n", BAD);
  689. X
  690. X  if (!ReadOK (fd, buf, 7))
  691. X    EasyFail("error reading screen descriptor\n", BAD);
  692. X
  693. X  /* Read image data */
  694. X  image->hdr.cols = cols = LM_to_uint(buf[0], buf[1]);
  695. X  image->hdr.rows = rows = LM_to_uint(buf[2], buf[3]);
  696. X  image->hdr.planes = 1;
  697. X  image->hdr.bits = depth = (buf[4] & 0x07) + 1;
  698. X  image->hdr.physbits = 8;
  699. X
  700. X  /* Pad to even byte */
  701. X  if (depth == 1)
  702. X  { image->hdr.rowlen = rowlen = 16 * ((cols + 15) / 16); }
  703. X  else
  704. X  { image->hdr.rowlen = rowlen = 2 * ((cols + 1) / 2); }
  705. X
  706. X  image->hdr.plnlen = rowlen * rows;
  707. X  colors = 1 << depth;
  708. X  image->hdr.clrlen = 3 * colors;
  709. X  image->hdr.title[0] = '\0';
  710. X  image->hdr.credits[0] = '\0';
  711. X  
  712. X  /* Try to guess aspect ratio */
  713. X  if (cols == 320 && rows == 200)    { image->hdr.aspect = 1.2; }
  714. X  else if (cols == 320 && rows == 175)    { image->hdr.aspect = 1.2; }
  715. X  else if (cols == 320 && rows == 400)    { image->hdr.aspect = 0.6; }
  716. X  else if (cols == 320 && rows == 350)    { image->hdr.aspect = 0.6; }
  717. X  else if (cols == 640 && rows == 200)    { image->hdr.aspect = 2.4; }
  718. X  else if (cols == 640 && rows == 175)    { image->hdr.aspect = 2.4; }
  719. X  else if (cols == 640 && rows == 400)    { image->hdr.aspect = 1.2; }
  720. X  else if (cols == 640 && rows == 350)    { image->hdr.aspect = 1.2; }
  721. X  else                    { image->hdr.aspect = 1.0; }
  722. X  
  723. X# ifdef DEBUG
  724. X  fprintf (stderr, "\nImage file header:\n\n");
  725. X  fprintf (stderr, "cols       %d\n", image->hdr.cols);
  726. X  fprintf (stderr, "rows       %d\n", image->hdr.rows);
  727. X  fprintf (stderr, "planes     %d\n", image->hdr.planes);
  728. X  fprintf (stderr, "bits       %d\n", image->hdr.bits);
  729. X  fprintf (stderr, "physbits   %d\n", image->hdr.physbits);
  730. X  fprintf (stderr, "rowlen     %d\n", image->hdr.rowlen);
  731. X  fprintf (stderr, "plnlen     %d\n", image->hdr.plnlen);
  732. X  fprintf (stderr, "clrlen     %d\n", image->hdr.clrlen);
  733. X  fprintf (stderr, "aspect     %1.3lf\n", image->hdr.aspect);
  734. X  fprintf (stderr, "title      '%s'\n", image->hdr.title);
  735. X  fprintf (stderr, "credits    '%s'\n", image->hdr.credits);
  736. X# endif
  737. X  
  738. X  /* Allocate image */
  739. X  alloc_fbm (image);
  740. X
  741. X  /* Read colormap if given */
  742. X  if ((buf[4] & 0x80) == 0x80)
  743. X  { if (ReadColorMap (fd, colors, image->cm) == BAD)
  744. X      return (BAD);
  745. X  }
  746. X
  747. X  while (1)
  748. X  { if (!ReadOK (fd, &c, 1))
  749. X      EasyFail("No image data -- EOF\n", BAD);
  750. X
  751. X    if (c == ';')
  752. X      return OK;
  753. X
  754. X    if (c == '!')
  755. X    { if (!ReadOK (fd, &c, 1))
  756. X        EasyFail("No extention function code -- EOF\n", BAD);
  757. X      if (IgnoreExtention(fd) == BAD)
  758. X        return (BAD);
  759. X    }
  760. X
  761. X    if (c != ',')
  762. X    { fprintf(stderr, "Bogus character ignoring '%c'\n", c);
  763. X      continue;
  764. X    }
  765. X
  766. X    if (count == 1)
  767. X      HardFail("This file contains more than one image! FAILING\n", 1);
  768. X    count++;
  769. X
  770. X    if (!ReadOK (fd, buf, 9))
  771. X      EasyFail("Couldn't read left/top/width/height\n", TRUE);
  772. X
  773. X# ifdef DEBUG
  774. X    fprintf (stderr, "Image description: ");
  775. X    for (i=0; i<9; i++) fprintf (stderr, "%02x", buf[i]);
  776. X    fprintf (stderr, "\n");
  777. X# endif
  778. X
  779. X    if ((buf[8] & 0x80) == 0x80)
  780. X      use_global_colormap = FALSE;
  781. X    else
  782. X      use_global_colormap = TRUE;
  783. X
  784. X    bit_pixel = 2 << (buf[8] & 0x07);
  785. X    
  786. X    if (!use_global_colormap && bit_pixel > colors)
  787. X    { HardFail ("Local colormap has more colors than global!\n", BAD); }
  788. X
  789. X    if (!use_global_colormap)
  790. X    { fprintf (stderr,
  791. X               "Overriding global colormap (%d) with local (%d)\n",
  792. X               colors, bit_pixel);
  793. X
  794. X      colors = bit_pixel;
  795. X      image->hdr.clrlen = 3 * colors;
  796. X      
  797. X      if (ReadColorMap(fd, colors, image->cm) == BAD)
  798. X        return BAD;
  799. X    }
  800. X
  801. X    fprintf (stderr, "Reading GIF image [%dx%d], %d bits",
  802. X         image->hdr.cols, image->hdr.rows, image->hdr.bits);
  803. X    if (image->hdr.clrlen > 0)
  804. X    { fprintf (stderr, ", %d colors", image->hdr.clrlen / 3); }
  805. X    else if (image->hdr.bits > 1)
  806. X    { fprintf (stderr, ", grayscale"); }
  807. X
  808. X    if ((buf[8] & 0x40) == 0x40)
  809. X    { fprintf (stderr, ", interlaced"); }
  810. X    fprintf (stderr, "\n");
  811. X
  812. X
  813. X    if ((buf[8] & 0x40) == 0x40)
  814. X    { 
  815. X      if (ReadInterlaced(fd,
  816. X             LM_to_uint(buf[4],buf[5]),
  817. X             LM_to_uint(buf[6],buf[7]),
  818. X             image->bm,
  819. X             rowlen) == BAD)
  820. X    return BAD;
  821. X    }
  822. X    else
  823. X    { if (ReadRaster(fd,
  824. X                     LM_to_uint(buf[4], buf[5]),
  825. X                     LM_to_uint(buf[6], buf[7]),
  826. X                     image->bm,
  827. X                     rowlen) == BAD)
  828. X        return BAD;
  829. X      else
  830. X        return OK;
  831. X    }
  832. X  }
  833. X}
  834. X
  835. XReadColorMap (fd, number, buffer)
  836. X  FILE           *fd;
  837. X  int             number;
  838. X  unsigned char   *buffer;
  839. X{
  840. X  int             i;
  841. X  unsigned char   rgb[3], *red, *grn, *blu;
  842. X
  843. X  red = buffer;
  844. X  grn = buffer + number;
  845. X  blu = grn + number;
  846. X
  847. X  for (i = 0; i < number; i++)
  848. X  { if (!ReadOK (fd, rgb, sizeof(rgb)))
  849. X      EasyFail("Bogus colormap\n", BAD);
  850. X
  851. X    red[i] = rgb[0];
  852. X    grn[i] = rgb[1];
  853. X    blu[i] = rgb[2];
  854. X  }
  855. X
  856. X  return OK;
  857. X}
  858. X
  859. XIgnoreExtention(fd)
  860. X  FILE           *fd;
  861. X{
  862. X  static char     buf[256];
  863. X  unsigned char   c;
  864. X
  865. X  while (1)
  866. X  {
  867. X    if (!ReadOK (fd, &c, 1))
  868. X      EasyFail("EOF in extention\n", BAD);
  869. X
  870. X    if (c == 0)
  871. X      return OK;
  872. X
  873. X    if (read(fd, buf, (int) c) != (int) c)
  874. X      EasyFail("EOF in extention\n", BAD);
  875. X  }
  876. X}
  877. X
  878. XGetCode(fd, code_size, flag)
  879. X  FILE           *fd;
  880. X  int             code_size;
  881. X  int             flag;
  882. X{
  883. X  static unsigned char buf[280];
  884. X  static int      curbit, lastbit, done, last_byte;
  885. X  int             i, j, ret;
  886. X  unsigned char   count;
  887. X
  888. X  if (flag)
  889. X  {
  890. X    curbit = 0;
  891. X    lastbit = 0;
  892. X    done = FALSE;
  893. X    return 0;
  894. X  }
  895. X
  896. X  if ((curbit + code_size) >= lastbit)
  897. X  { if (done)
  898. X    { if (curbit >= lastbit)
  899. X        EasyFail("Ran off the end of my bits\n", -1);
  900. X    }
  901. X    buf[0] = buf[last_byte - 2];
  902. X    buf[1] = buf[last_byte - 1];
  903. X
  904. X    if (!ReadOK (fd, &count, 1))
  905. X    { EasyFail("Error in getting buffer size\n", -1); }
  906. X
  907. X    if (count == 0)
  908. X    { done = TRUE; } 
  909. X
  910. X    else if (!ReadOK (fd, &buf[2], count))
  911. X      EasyFail("Error in getting buffer\n", -1);
  912. X
  913. X    last_byte = 2 + count;
  914. X    curbit = (curbit - lastbit) + 16;
  915. X    lastbit = (2 + count) * 8;
  916. X  }
  917. X
  918. X  ret = 0;
  919. X
  920. X  for (i = curbit, j = 0; j < code_size; i++, j++)
  921. X    ret |= ((buf[i / 8] & (1 << (i % 8))) != 0) << j;
  922. X
  923. X  curbit += code_size;
  924. X
  925. X  return ret;
  926. X}
  927. X
  928. XLWZReadByte(fd, flag, input_code_size)
  929. X  FILE           *fd;
  930. X  int             flag;
  931. X  int             input_code_size;
  932. X{
  933. X  static int      fresh = FALSE;
  934. X  int             code, incode;
  935. X  static int      code_size, set_code_size;
  936. X  static int      max_code, max_code_size;
  937. X  static int      firstcode, oldcode;
  938. X  static int      clear_code, end_code;
  939. X  static int      table[2][(1 << MAX_LWZ_BITS)];
  940. X  static int      stack[(1 << (MAX_LWZ_BITS)) * 2], *sp;
  941. X  register int    i;
  942. X
  943. X  if (flag)
  944. X  {
  945. X    set_code_size = input_code_size;
  946. X    code_size = set_code_size + 1;
  947. X    clear_code = 1 << set_code_size;
  948. X    end_code = clear_code + 1;
  949. X    max_code_size = 2 * clear_code;
  950. X    max_code = clear_code + 2;
  951. X
  952. X    GetCode(fd, NULL, NULL);
  953. X
  954. X    fresh = TRUE;
  955. X
  956. X    for (i = 0; i < clear_code; i++)
  957. X    {
  958. X      table[0][i] = 0;
  959. X      table[1][i] = i;
  960. X    }
  961. X
  962. X    for (; i < (1 << MAX_LWZ_BITS); i++)
  963. X      table[0][i] = table[1][0] = 0;
  964. X
  965. X    sp = stack;
  966. X    return 0;
  967. X  }
  968. X  else if (fresh)
  969. X  { fresh = FALSE;
  970. X    do
  971. X    { firstcode = oldcode =
  972. X        GetCode(fd, code_size, FALSE);
  973. X    } while (firstcode == clear_code);
  974. X
  975. X    return firstcode;
  976. X  }
  977. X
  978. X  if (sp > stack)
  979. X    return *--sp;
  980. X
  981. X  while ((code = GetCode(fd, code_size, FALSE)) >= 0)
  982. X  { if (code == clear_code)
  983. X    { for (i = 0; i < clear_code; i++)
  984. X      {table[0][i] = 0;
  985. X        table[1][i] = i;
  986. X      }
  987. X
  988. X      for (; i < (1 << MAX_LWZ_BITS); i++)
  989. X        table[0][i] = table[1][i] = 0;
  990. X
  991. X      code_size = set_code_size + 1;
  992. X      max_code_size = 2 * clear_code;
  993. X      max_code = clear_code + 2;
  994. X      sp = stack;
  995. X      firstcode = oldcode =
  996. X        GetCode(fd, code_size, FALSE);
  997. X      return firstcode;
  998. X    }
  999. X    else if (code == end_code)
  1000. X    { unsigned char   count;
  1001. X      unsigned char   junk;
  1002. X
  1003. X      while (ReadOK (fd, &count, 1) && (count != 0))
  1004. X        while (count-- != 0 && ReadOK (fd, &junk, 1));
  1005. X
  1006. X      if (count != 0)
  1007. X        EasyFail("missing EOD in data stream (common occurance)\n", -3);
  1008. X
  1009. X      return -2;
  1010. X    }
  1011. X
  1012. X    incode = code;
  1013. X
  1014. X    if (code >= max_code)
  1015. X    { *sp++ = firstcode;
  1016. X      code = oldcode;
  1017. X    }
  1018. X
  1019. X    while (code >= clear_code)
  1020. X    {
  1021. X      *sp++ = table[1][code];
  1022. X      if (code == table[0][code])
  1023. X        EasyFail("Circular table entry BIG ERROR\n", -1);
  1024. X      code = table[0][code];
  1025. X    }
  1026. X
  1027. X    *sp++ = firstcode = table[1][code];
  1028. X
  1029. X    if ((code = max_code) < (1 << MAX_LWZ_BITS))
  1030. X    {
  1031. X      table[0][code] = oldcode;
  1032. X      table[1][code] = firstcode;
  1033. X      max_code++;
  1034. X
  1035. X      if ((max_code >= max_code_size) &&
  1036. X          (max_code_size < (1 << MAX_LWZ_BITS)))
  1037. X      {
  1038. X        max_code_size *= 2;
  1039. X        code_size++;
  1040. X      }
  1041. X    }
  1042. X    oldcode = incode;
  1043. X
  1044. X    if (sp > stack)
  1045. X      return *--sp;
  1046. X  }
  1047. X
  1048. X  return code;
  1049. X}
  1050. X
  1051. XReadInterlaced(fd, len, height, buffer, rowlen)
  1052. X  FILE           *fd;
  1053. X  int             len, height;
  1054. X  unsigned char     *buffer;
  1055. X  int          rowlen;
  1056. X{
  1057. X  unsigned char   c;
  1058. X  register unsigned char *bmp;
  1059. X  register int    v;
  1060. X  register int    xpos = 0;
  1061. X  register int    ypos = 0, pass = 0;
  1062. X  register int    maxypos = 0;
  1063. X
  1064. X
  1065. X  if (!ReadOK(fd, &c, 1))
  1066. X    EasyFail("Bogus image data -- EOF\n", BAD);
  1067. X  if (LWZReadByte(fd, TRUE, c) < 0)
  1068. X    return BAD;
  1069. X
  1070. X  while ((v = LWZReadByte(fd, FALSE, c)) >= 0)
  1071. X  {
  1072. X    if (xpos == 0)
  1073. X    { bmp = &(buffer[ypos * rowlen]);
  1074. X      if (ypos > height)
  1075. X      { fprintf (stderr, "Wanring Too much data, started to read line %d\n",
  1076. X         ypos);
  1077. X        return (OK);
  1078. X      }
  1079. X    }
  1080. X    
  1081. X    *bmp++ = v;
  1082. X
  1083. X    if (++xpos == len)
  1084. X    {
  1085. X      xpos = 0;
  1086. X      switch (pass)
  1087. X      {
  1088. X       case 0: case 1:        ypos += 8; break;
  1089. X       case 2:            ypos += 4; break;
  1090. X       case 3:            ypos += 2; break;
  1091. X      }
  1092. X      
  1093. X      if (ypos > maxypos)    maxypos = ypos;
  1094. X
  1095. X      if (ypos >= height)
  1096. X      {
  1097. X    switch (++pass)
  1098. X    {
  1099. X     case 1:        ypos = 4; break;
  1100. X     case 2:        ypos = 2; break;
  1101. X     case 3:        ypos = 1; break;
  1102. X    }
  1103. X      }
  1104. X    }
  1105. X  }
  1106. X
  1107. X  if (maxypos >= height) return OK;
  1108. X
  1109. X  if (v == (-2))
  1110. X    return OK;
  1111. X  return BAD;
  1112. X}
  1113. X
  1114. XReadRaster (fd, len, height, buffer, rowlen)
  1115. X  FILE           *fd;
  1116. X  int             len, height;
  1117. X  unsigned char  *buffer;
  1118. X  int             rowlen;
  1119. X{
  1120. X  unsigned char   c;
  1121. X  register unsigned char  *bmp;
  1122. X  register int    v;
  1123. X  register int    xpos = 0;
  1124. X  register int    ypos = 0;
  1125. X
  1126. X  if (!ReadOK (fd, &c, 1))
  1127. X    EasyFail("Bogus image data -- EOF\n", TRUE);
  1128. X
  1129. X  if (LWZReadByte(fd, TRUE, c) < 0)
  1130. X    return BAD;
  1131. X
  1132. X  /* Read the raster data and dump it into the FBM bitmap */
  1133. X  while ((v = LWZReadByte(fd, FALSE, c)) >= 0)
  1134. X  {
  1135. X    if (xpos == 0)
  1136. X    { bmp = &(buffer[ypos++ * rowlen]);
  1137. X      if (ypos > height)
  1138. X      { fprintf (stderr, "Warning: too much data, started to read line %d\n",
  1139. X         ypos);
  1140. X        return (OK);
  1141. X      }
  1142. X    }
  1143. X    
  1144. X    *bmp++ = v;
  1145. X    
  1146. X    if (++xpos == len)
  1147. X
  1148. X    if (xpos == len) xpos = 0;
  1149. X  }
  1150. X
  1151. X  fprintf (stderr, "Done storing bitmap, xpos %d, ypos %d [%dx%d]\n",
  1152. X           xpos, ypos, len, height);
  1153. X
  1154. X  if (ypos >= height) return OK;
  1155. X
  1156. X  if (v == (-2))
  1157. X    return OK;
  1158. X  return BAD;
  1159. X}
  1160. END_OF_FILE
  1161. if test 13672 -ne `wc -c <'flgifr.c'`; then
  1162.     echo shar: \"'flgifr.c'\" unpacked with wrong size!
  1163. fi
  1164. # end of 'flgifr.c'
  1165. fi
  1166. if test -f 'fliff.c' -a "${1}" != "-c" ; then 
  1167.   echo shar: Will not clobber existing file \"'fliff.c'\"
  1168. else
  1169. echo shar: Extracting \"'fliff.c'\" \(23454 characters\)
  1170. sed "s/^X//" >'fliff.c' <<'END_OF_FILE'
  1171. X/*****************************************************************
  1172. X * fliff.c: FBM Library 0.9 (Beta test) 07-Mar-89  Michael Mauldin
  1173. X *
  1174. X * Copyright (C) 1989 by Michael Mauldin.  Permission is granted to
  1175. X * use this file in whole or in part provided that you do not sell it
  1176. X * for profit and that this copyright notice is retained unchanged.
  1177. X *
  1178. X * fliff.c: 
  1179. X *
  1180. X * CONTENTS
  1181. X *    write_iff (image, stream)
  1182. X *    read_iff (image, stream, mstr, mlen)
  1183. X *
  1184. X * EDITLOG
  1185. X *    LastEditDate = Mon Mar 20 18:54:08 1989 - Michael Mauldin
  1186. X *    LastFileName = /usr2/mlm/src/misc/fbm/fliff.c
  1187. X *
  1188. X * HISTORY
  1189. X * 07-Mar-89  Michael Mauldin (mlm) at Carnegie Mellon University
  1190. X *    Beta release (version 0.9) mlm@cs.cmu.edu
  1191. X *
  1192. X * 04-Mar-89  Michael Mauldin (mlm) at Carnegie Mellon University
  1193. X *    Read and Write support for Amiga IFF (except HAM mode)
  1194. X *****************************************************************/
  1195. X
  1196. X# include <stdio.h>
  1197. X# include <math.h>
  1198. X# include <ctype.h>
  1199. X# include "fbm.h"
  1200. X
  1201. X#ifndef lint
  1202. Xstatic char *fbmid =
  1203. X    "$FBM fliff.c <0.9> 07-Mar-89  (C) 1989 by Michael Mauldin$";
  1204. X#endif
  1205. X
  1206. X/****************************************************************
  1207. X * from iff.h
  1208. X ****************************************************************/
  1209. X
  1210. X# define BOOL    int        /*  1 bit value            */
  1211. X# define SBYTE    char        /*  8 bits signend        */
  1212. X# define UBYTE    unsigned char    /*  8 bits unsigned        */
  1213. X# define WORD    short        /* 16 bits signed        */
  1214. X# define UWORD    unsigned short    /* 16 bits unsigned        */
  1215. X# define LONG    long        /* 32 bits signed        */
  1216. X# define ID    long
  1217. X# define MakeID(a,b,c,d)  ( (LONG)(a)<<24L | (LONG)(b)<<16L | (c)<<8 | (d) )
  1218. X# define FORM MakeID('F','O','R','M')
  1219. X# define PROP MakeID('P','R','O','P')
  1220. X# define LIST MakeID('L','I','S','T')
  1221. X# define CAT  MakeID('C','A','T',' ')
  1222. X# define FILLER MakeID(' ',' ',' ',' ')
  1223. X# define NULL_CHUNK 0L           /* No current chunk.*/
  1224. X# define TRUE    1
  1225. X# define FALSE    0
  1226. X
  1227. X
  1228. X/* ---------- Chunk ----------------------------------------------------*/
  1229. X
  1230. X/* All chunks start with a type ID and a count of the data bytes that 
  1231. X   follow--the chunk's "logical size" or "data size". If that number is odd,
  1232. X   a 0 pad byte is written, too. */
  1233. X
  1234. Xtypedef struct {
  1235. X    ID      ckID;
  1236. X    LONG  ckSize;
  1237. X    } ChunkHeader;
  1238. X
  1239. Xtypedef struct {
  1240. X    ID      ckID;
  1241. X    LONG  ckSize;
  1242. X    UBYTE ckData[ 1 /*REALLY: ckSize*/ ];
  1243. X    } Chunk;
  1244. X
  1245. X/*----------------------------------------------------------------------*
  1246. X * ILBM.H  Definitions for InterLeaved BitMap raster image.     1/23/86
  1247. X *
  1248. X * By Jerry Morrison and Steve Shaw, Electronic Arts.
  1249. X * This software is in the public domain.
  1250. X *
  1251. X * This version for the Commodore-Amiga computer.
  1252. X *----------------------------------------------------------------------*/
  1253. X
  1254. X# define ID_ILBM MakeID('I','L','B','M')
  1255. X# define ID_BMHD MakeID('B','M','H','D')
  1256. X# define ID_CMAP MakeID('C','M','A','P')
  1257. X# define ID_GRAB MakeID('G','R','A','B')
  1258. X# define ID_DEST MakeID('D','E','S','T')
  1259. X# define ID_SPRT MakeID('S','P','R','T')
  1260. X# define ID_CAMG MakeID('C','A','M','G')
  1261. X# define ID_BODY MakeID('B','O','D','Y')
  1262. X
  1263. X/* ---------- BitMapHeader ---------------------------------------------*/
  1264. X
  1265. Xtypedef UBYTE Masking;        /* Choice of masking technique.*/
  1266. X# define mskNone                 0
  1267. X# define mskHasMask              1
  1268. X# define mskHasTransparentColor  2
  1269. X# define mskLasso                3
  1270. X
  1271. Xtypedef UBYTE Compression;    /* Choice of compression algorithm applied to
  1272. X     * each row of the source and mask planes. "cmpByteRun1" is the byte run
  1273. X     * encoding generated by Mac's PackBits. See Packer.h . */
  1274. X# define cmpNone      0
  1275. X# define cmpByteRun1  1
  1276. X
  1277. X/* Aspect ratios: The proper fraction xAspect/yAspect represents the pixel
  1278. X * aspect ratio pixel_width/pixel_height.
  1279. X *
  1280. X * For the 4 Amiga display modes:
  1281. X *   320 x 200: 10/11  (these pixels are taller than they are wide)
  1282. X *   320 x 400: 20/11
  1283. X *   640 x 200:  5/11
  1284. X *   640 x 400: 10/11        */
  1285. X# define x320x200Aspect 10
  1286. X# define y320x200Aspect 11
  1287. X# define x320x400Aspect 20
  1288. X# define y320x400Aspect 11
  1289. X# define x640x200Aspect  5
  1290. X# define y640x200Aspect 11
  1291. X# define x640x400Aspect 10
  1292. X# define y640x400Aspect 11
  1293. X
  1294. X/* A BitMapHeader is stored in a BMHD chunk. */
  1295. Xtypedef struct {
  1296. X    UWORD w, h;            /* raster width & height in pixels */
  1297. X    WORD  x, y;            /* position for this image */
  1298. X    UBYTE nPlanes;        /* # source bitplanes */
  1299. X    Masking masking;        /* masking technique */
  1300. X    Compression compression;    /* compression algorithm */
  1301. X    UBYTE pad1;            /* UNUSED.  For consistency, put 0 here.*/
  1302. X    UWORD transparentColor;    /* transparent "color number" */
  1303. X    UBYTE xAspect, yAspect;    /* aspect ratio, a rational number x/y */
  1304. X    WORD  pageWidth, pageHeight;  /* source "page" size in pixels */
  1305. X    } BitMapHeader;
  1306. X
  1307. X/* RowBytes computes the number of bytes in a row, from the width in pixels.*/
  1308. X# define RowBytes(w)   (2 * (((w) + 15) / 16))
  1309. X
  1310. X
  1311. X/* ---------- ColorRegister --------------------------------------------*/
  1312. X/* A CMAP chunk is a packed array of ColorRegisters (3 bytes each). */
  1313. Xtypedef struct {
  1314. X    UBYTE red, green, blue;   /* MUST be UBYTEs so ">> 4" won't sign extend.*/
  1315. X    } ColorRegister;
  1316. X
  1317. X/* Use this constant instead of sizeof(ColorRegister). */
  1318. X# define sizeofColorRegister  3
  1319. X
  1320. Xtypedef WORD Color4;    /* Amiga RAM version of a color-register,
  1321. X             * with 4 bits each RGB in low 12 bits.*/
  1322. X
  1323. X# define swapword(X)    ((((X) & 0xff) << 8) | (((X) & 0xff00) >> 8))
  1324. X# define swaplong(X)    (((unsigned) ((X) & 0xff000000) >> 24) |    \
  1325. X             ((unsigned) ((X) & 0x00ff0000) >> 8) |    \
  1326. X             ((unsigned) ((X) & 0x0000ff00) << 8) |    \
  1327. X             ((unsigned) ((X) & 0x000000ff) << 24))
  1328. X
  1329. X# define swapsize(X) ((machine_byte_order () == LITTLE) ? swaplong(X) : (X))
  1330. X
  1331. X/* Maximum number of bitplanes in RAM. Current Amiga max w/dual playfield. */
  1332. X# define MaxAmDepth 6
  1333. X
  1334. X/* Chunks must be padded to align to even boundaries */
  1335. X# define EVENALIGN(X) (((X) + 1) & ~1)
  1336. X
  1337. X/* ---------- Point2D --------------------------------------------------*/
  1338. X/* A Point2D is stored in a GRAB chunk. */
  1339. Xtypedef struct {
  1340. X    WORD x, y;        /* coordinates (pixels) */
  1341. X    } Point2D;
  1342. X
  1343. X/* ---------- DestMerge ------------------------------------------------*/
  1344. X/* A DestMerge is stored in a DEST chunk. */
  1345. Xtypedef struct {
  1346. X    UBYTE depth;    /* # bitplanes in the original source */
  1347. X    UBYTE pad1;        /* UNUSED; for consistency store 0 here */
  1348. X    UWORD planePick;    /* how to scatter source bitplanes into destination */
  1349. X    UWORD planeOnOff;    /* default bitplane data for planePick */
  1350. X    UWORD planeMask;    /* selects which bitplanes to store into */
  1351. X    } DestMerge;
  1352. X
  1353. X/* ---------- SpritePrecedence -----------------------------------------*/
  1354. X/* A SpritePrecedence is stored in a SPRT chunk. */
  1355. Xtypedef UWORD SpritePrecedence;
  1356. X
  1357. X/* ---------- Viewport Mode --------------------------------------------*/
  1358. X/* A Commodore Amiga ViewPort->Modes is stored in a CAMG chunk. */
  1359. X/* The chunk's content is declared as a LONG. */
  1360. X
  1361. X/* ---------- CRange ---------------------------------------------------*/
  1362. X/* A CRange is store in a CRNG chunk. */
  1363. Xtypedef struct {
  1364. X    WORD  pad1;        /* reserved for future use; store 0 here */
  1365. X    WORD  rate;        /* color cycling rate, 16384 = 60 steps/second */
  1366. X    WORD  active;    /* nonzero means color cycling is turned on */
  1367. X    UBYTE low, high;    /* lower and upper color registers selected */
  1368. X    } CRange;
  1369. X
  1370. X/*----------------------------------------------------------------------*
  1371. X * PACKER.H  typedefs for Data-Compresser.                  1/22/86
  1372. X *
  1373. X * This module implements the run compression algorithm "cmpByteRun1"; the
  1374. X * same encoding generated by Mac's PackBits.
  1375. X *
  1376. X * By Jerry Morrison and Steve Shaw, Electronic Arts.
  1377. X * This software is in the public domain.
  1378. X *
  1379. X * This version for the Commodore-Amiga computer.
  1380. X *----------------------------------------------------------------------*/
  1381. X
  1382. X/* This macro computes the worst case packed size of a "row" of bytes. */
  1383. X# define MaxPackedSize(rowSize)  ( (rowSize) + ( ((rowSize)+127) >> 7 ) )
  1384. X
  1385. X/*----------------------------------------------------------------------*
  1386. X * unpacker.c Convert data from "cmpByteRun1" run compression. 11/15/85
  1387. X *
  1388. X * By Jerry Morrison and Steve Shaw, Electronic Arts.
  1389. X * This software is in the public domain.
  1390. X *
  1391. X *    control bytes:
  1392. X *     [0..127]   : followed by n+1 bytes of data.
  1393. X *     [-1..-127] : followed by byte to be repeated (-n)+1 times.
  1394. X *     -128       : NOOP.
  1395. X *
  1396. X * This version for the Commodore-Amiga computer.
  1397. X *----------------------------------------------------------------------*/
  1398. X
  1399. X/*----------- UnPackRow ------------------------------------------------*/
  1400. X
  1401. X# define UGetByte()    (*source++)
  1402. X# define UPutByte(c)    (*dest++ = (c))
  1403. X
  1404. X/* Given POINTERS to POINTER variables, unpacks one row, updating the source
  1405. X * and destination pointers until it produces dstBytes bytes. */
  1406. Xstatic UnPackRow(pSource, pDest, srcBytes0, dstBytes0)
  1407. X    char **pSource, **pDest;  int srcBytes0, dstBytes0; {
  1408. X    register char *source = *pSource;
  1409. X    register char *dest   = *pDest;
  1410. X    register int n;
  1411. X    register char c;
  1412. X    register int srcBytes = srcBytes0, dstBytes = dstBytes0;
  1413. X    BOOL error = TRUE;    /* assume error until we make it through the loop */
  1414. X
  1415. X
  1416. X# ifdef DEBUG
  1417. X    fprintf (stderr, "Unpack called, src %d, dst %d\n",
  1418. X             srcBytes0, dstBytes0);
  1419. X# endif
  1420. X
  1421. X    while( dstBytes > 0 )  {
  1422. X    if ( (srcBytes -= 1) < 0 )  goto ErrorExit;
  1423. X        n = UGetByte() & 0x0ff;
  1424. X
  1425. X        if (n < 128) {
  1426. X# ifdef DEBUG
  1427. X            fprintf (stderr, "Got %02x, copying %d bytes...\n", n, n+1);
  1428. X# endif
  1429. X
  1430. X        n += 1;
  1431. X        
  1432. X        if ( (srcBytes -= n) < 0 )  goto ErrorExit;
  1433. X        if ( (dstBytes -= n) < 0 )  goto ErrorExit;
  1434. X        do {  UPutByte(UGetByte());  } while (--n > 0);
  1435. X        }
  1436. X
  1437. X        else if (n != 128) {
  1438. X# ifdef DEBUG
  1439. X            fprintf (stderr, "Got %02x, repeating byte %d times...\n",
  1440. X            n, 257-n);
  1441. X# endif
  1442. X
  1443. X        n = 257 - n;
  1444. X        
  1445. X        if ( (srcBytes -= 1) < 0 )  goto ErrorExit;
  1446. X        if ( (dstBytes -= n) < 0 )  goto ErrorExit;
  1447. X        c = UGetByte();
  1448. X        do {  UPutByte(c);  } while (--n > 0);
  1449. X        }
  1450. X    }
  1451. X    error = FALSE;    /* success! */
  1452. X
  1453. X  ErrorExit:
  1454. X    *pSource = source;  *pDest = dest;
  1455. X    
  1456. X    if (error)
  1457. X    { fprintf (stderr, "error in unpack, src %d, dst %d\n", 
  1458. X           srcBytes, dstBytes);
  1459. X    }
  1460. X    
  1461. X    return(error);
  1462. X    }
  1463. X
  1464. X/****************************************************************
  1465. X * read_iff: Read an Amiga format IFF Interleaved Bitmap
  1466. X ****************************************************************/
  1467. X
  1468. Xread_iff (image, rfile, mstr, mlen)
  1469. XFBM *image;
  1470. XFILE *rfile;
  1471. Xchar *mstr;
  1472. Xint mlen;
  1473. X{ char magic[8];
  1474. X  long formsize, buflen;
  1475. X  Chunk *form;
  1476. X  int result;
  1477. X
  1478. X  /* First word is magic number */
  1479. X  magic[0] = NEXTMCH(rfile,mstr,mlen) & 0xff;
  1480. X  magic[1] = NEXTMCH(rfile,mstr,mlen) & 0xff;
  1481. X  magic[2] = NEXTMCH(rfile,mstr,mlen) & 0xff;
  1482. X  magic[3] = NEXTMCH(rfile,mstr,mlen) & 0xff;
  1483. X  magic[4] = '\0';
  1484. X
  1485. X  /* If magic number is not FORM, lose */
  1486. X  if (strcmp (magic, "FORM") != 0)
  1487. X  { if (strncmp (magic, "FOR", 3) == 0 ||
  1488. X    strncmp (magic, "LIS", 3) == 0 ||
  1489. X    strncmp (magic, "CAT", 3) == 0)
  1490. X    { fprintf (stderr, "Sorry, I only handle FORM type IFF files\n");
  1491. X      return (0);
  1492. X    }
  1493. X    
  1494. X    fprintf (stderr,
  1495. X         "read_iff: error, file not a FORM type IFF file, magic '%s'\n",
  1496. X          magic);
  1497. X    return (0);
  1498. X  }
  1499. X
  1500. X  /* Second longword is length of data chunk */
  1501. X  formsize = get_long (rfile, BIG);  
  1502. X  
  1503. X  form = (Chunk *) malloc (formsize + 8);
  1504. X  form->ckID = FORM;
  1505. X  form->ckSize = formsize;
  1506. X
  1507. X  /* Now read the rest of the chunk */
  1508. X  if ((buflen = fread (form->ckData, 1, formsize, stdin)) < formsize)
  1509. X  { if (buflen < 0)
  1510. X    { perror ("stdin"); }
  1511. X    else
  1512. X    { fprintf (stderr, "error: premature EOF in FORM after %d of %d bytes\n",
  1513. X           buflen, formsize);
  1514. X    }
  1515. X
  1516. X    exit (1);
  1517. X  }
  1518. X
  1519. X  /* Recursively parse the FORM */  
  1520. X  result = parse_form (image, form);
  1521. X
  1522. X  /* Now we've read the image (or not) */  
  1523. X  free (form);
  1524. X
  1525. X  return (result);
  1526. X}
  1527. X
  1528. X/****************************************************************
  1529. X * parse_form: Parse an IFF form chunk
  1530. X *
  1531. X *    FORM       ::= "FORM" #{ FormType (LocalChunk | FORM | LIST | CAT)* }
  1532. X *    FormType   ::= ID
  1533. X *    LocalChunk ::= Property | Chunk
  1534. X ****************************************************************/
  1535. X
  1536. Xparse_form (image, chunk)
  1537. XFBM *image;
  1538. XChunk *chunk;
  1539. X{ register UBYTE *data, *tail;
  1540. X  register int clrlen, colors;
  1541. X  register BitMapHeader *bmh;
  1542. X  register int i, bits;
  1543. X  long formtype;
  1544. X  int found_bmhd=0, found_cmap=0, found_body=0;
  1545. X  Chunk *part;
  1546. X
  1547. X  data = chunk->ckData;
  1548. X  tail = data + chunk->ckSize;  
  1549. X  
  1550. X  formtype = MakeID(data[0], data[1], data[2], data[3]);
  1551. X  data += 4;
  1552. X  
  1553. X  if (formtype != ID_ILBM)
  1554. X  { fprintf (stderr, "this FORM doesn't start with ILBM, but %4.4s, sorry.\n",
  1555. X         &formtype);
  1556. X    return (0);
  1557. X  }
  1558. X  
  1559. X  while (data < tail)
  1560. X  { part = (Chunk *) data;
  1561. X    part->ckID   = swapsize (part->ckID);
  1562. X    part->ckSize = swapsize (part->ckSize);
  1563. X    data += ( EVENALIGN (part->ckSize) + 8 );
  1564. X    
  1565. X# ifdef DEBUG
  1566. X    fprintf (stderr, "Found %c%c%c%c, size %ld\n",
  1567. X        (part->ckID & 0xff000000) >> 24,
  1568. X        (part->ckID & 0x00ff0000) >> 16,
  1569. X        (part->ckID & 0x0000ff00) >>  8,
  1570. X        (part->ckID & 0x000000ff),
  1571. X        part->ckSize);
  1572. X# endif
  1573. X
  1574. X    if (part->ckID == ID_BMHD)
  1575. X    { found_bmhd++;
  1576. X      bmh = (BitMapHeader *) part->ckData;
  1577. X      
  1578. X      /* IFF uses BIG byte order, swap if necessary */
  1579. X      if (machine_byte_order () == LITTLE)
  1580. X      { bmh->w = swapword (bmh->w);
  1581. X        bmh->h = swapword (bmh->h);
  1582. X    bmh->x = swapword (bmh->x);
  1583. X    bmh->y = swapword (bmh->y);
  1584. X    bmh->transparentColor = swapword (bmh->transparentColor);
  1585. X    bmh->pageWidth = swapword (bmh->pageWidth);
  1586. X    bmh->pageHeight = swapword (bmh->pageHeight);
  1587. X      }
  1588. X      
  1589. X      image->hdr.rows = bmh->h;
  1590. X      image->hdr.cols = bmh->w;
  1591. X      image->hdr.planes = 1;
  1592. X      image->hdr.bits = bmh->nPlanes;
  1593. X      image->hdr.physbits = 8;
  1594. X      image->hdr.rowlen = 16 * ((image->hdr.cols + 15) / 16);
  1595. X      image->hdr.plnlen = image->hdr.rowlen * image->hdr.rows;
  1596. X      image->hdr.clrlen = 0;
  1597. X      image->hdr.aspect = (double) bmh->yAspect / bmh->xAspect;
  1598. X      image->hdr.title[0] = '\0';
  1599. X      image->hdr.credits[0] = '\0';
  1600. X    }
  1601. X    else if (part->ckID == ID_CMAP)
  1602. X    { image->hdr.clrlen = part->ckSize;
  1603. X
  1604. X      alloc_fbm (image);
  1605. X
  1606. X      clrlen = image->hdr.clrlen;
  1607. X      colors = clrlen / 3;
  1608. X
  1609. X      for (i=0; i<image->hdr.clrlen; i++)
  1610. X      { image->cm[(colors * (i%3)) + i/3] = part->ckData[i]; }
  1611. X
  1612. X      /* Compute number of bits in colormap */
  1613. X      for (i=colors, bits=1; i > 2; i /= 2, bits++) ;
  1614. X      
  1615. X      if (bits < image->hdr.bits) image->hdr.bits = bits;
  1616. X
  1617. X      found_cmap++;
  1618. X    }
  1619. X    else if (part->ckID == ID_BODY)
  1620. X    { if (!found_bmhd)
  1621. X      { fprintf (stderr, "Error, BODY found with no BMHD header\n");
  1622. X        return (0);
  1623. X      }
  1624. X      
  1625. X      if (found_cmap == 0)
  1626. X      { alloc_fbm (image); }
  1627. X      
  1628. X      found_body++;
  1629. X      
  1630. X      /* Decode body */
  1631. X      fprintf (stderr, "Reading IFF [%dx%dx%d], %d physbits, %1.3lf aspect",
  1632. X        image->hdr.cols, image->hdr.rows,
  1633. X        image->hdr.bits, image->hdr.physbits,
  1634. X        image->hdr.aspect);
  1635. X      if (image->hdr.planes > 1)
  1636. X      { fprintf (stderr, ", %d planes", image->hdr.planes); }
  1637. X      if (image->hdr.clrlen > 1)
  1638. X      { fprintf (stderr, ", %d colors", image->hdr.clrlen / 3); }
  1639. X      if (bmh->compression)
  1640. X      { fprintf (stderr, ", compressed"); }
  1641. X      if (bmh->masking == mskHasMask)
  1642. X      { fprintf (stderr, ", with mask"); }
  1643. X      fprintf (stderr, "\n");
  1644. X
  1645. X# ifdef DEBUG
  1646. X      fprintf (stderr,
  1647. X           "masking %d, compression %d, transparent %d, page [%dx%d]\n",
  1648. X           bmh->masking, bmh->compression, bmh->transparentColor,
  1649. X           bmh->pageWidth, bmh->pageHeight);
  1650. X
  1651. X    for (i=0; i<colors; i++)
  1652. X    { fprintf (stderr, "    color %3d:  <%3d, %3d, %3d>\n", i,
  1653. X           image->cm[i], image->cm[i+colors], image->cm[i+colors*2]);
  1654. X    }
  1655. X# endif
  1656. X      
  1657. X      return (read_iff_body (image, bmh, part));
  1658. X    }
  1659. X  }
  1660. X  
  1661. X  return (0);
  1662. X}
  1663. X
  1664. X/****************************************************************
  1665. X * read_iff_body: Read the bits in the ILBM body into the FBM image
  1666. X ****************************************************************/
  1667. X
  1668. Xread_iff_body (image, bmh, body)
  1669. XFBM *image;
  1670. XBitMapHeader *bmh;
  1671. XChunk *body;
  1672. X{ register int r, c, k, pmask, byte, bit;
  1673. X  unsigned char *row, *bp, *buf, *obm, *tail;
  1674. X  int bytlen = image->hdr.cols / 8;
  1675. X  int planes =  bmh->nPlanes + ((bmh->masking == mskHasMask) ? 1 : 0);
  1676. X  
  1677. X  buf = (unsigned char *) malloc (bytlen);
  1678. X  
  1679. X  bp = body->ckData;
  1680. X  tail = bp + body->ckSize;
  1681. X
  1682. X# ifdef DEBUG
  1683. X  fprintf (stderr, "Body length %d, planes %d: ", tail-bp, planes);
  1684. X  for (c=0; c<20; c++) fprintf (stderr, "%02x", bp[c]);
  1685. X  fprintf (stderr, "\n");
  1686. X# endif
  1687. X
  1688. X  /* Each iteration reads one scan line */
  1689. X  for (r=0; r<image->hdr.rows; r++)
  1690. X  {
  1691. X    if (bp > tail)
  1692. X    { fprintf (stderr, "Ran out of data in body after %d of %d rows\n",
  1693. X        r, image->hdr.rows);
  1694. X      return (0);
  1695. X    }
  1696. X
  1697. X    obm = &(image->bm[r * image->hdr.rowlen]);
  1698. X
  1699. X    /* Clear the output row of pixels */
  1700. X    for (c=0; c<image->hdr.cols; c++)
  1701. X    { obm[c] = 0; }
  1702. X
  1703. X    /* Each loop reads one plane of this scan line */    
  1704. X    for (k=0; k<planes; k++)
  1705. X    {
  1706. X      /* First get pointer to data packed 8 bits per byte */
  1707. X      if (bmh->compression == 0)
  1708. X      { row = bp; bp += RowBytes (bmh->w); }
  1709. X      else
  1710. X      { row = buf;
  1711. X        if (UnPackRow (&bp, &row, (int) (tail-bp), RowBytes (bmh->w)) != 0)
  1712. X        { fprintf (stderr,
  1713. X           "%s, row %d of %d, plane %d of %d, bytes per row %d\n",
  1714. X           "Error in UnPackRow",
  1715. X           r, image->hdr.rows, k, planes, RowBytes (bmh->w));
  1716. X      return (0);
  1717. X    }
  1718. X    row = buf;
  1719. X      }
  1720. X
  1721. X      /* Ignore extra planes (including the mask if any) */
  1722. X      if (k >= image->hdr.bits)
  1723. X        continue;
  1724. X
  1725. X      /* Now OR in these bits into the output pixels */
  1726. X      pmask = 1 << k;
  1727. X
  1728. X      for (c=0; c<image->hdr.cols; c++)
  1729. X      { byte = c >> 3;
  1730. X        bit = 7 - (c & 7);
  1731. X    bit = row[byte] & (1 << bit);
  1732. X
  1733. X    obm[c] |= bit ? pmask : 0;
  1734. X      }
  1735. X    }
  1736. X  }
  1737. X
  1738. X  if (tail-bp > 1)
  1739. X  { fprintf (stderr, "Warning, %d bytes of data unread\n", tail - bp); }
  1740. X  
  1741. X  return (1);
  1742. X}
  1743. X
  1744. X/****************************************************************
  1745. X * write_iff: Write AMIGA IFF format ILBM file
  1746. X *
  1747. X * Writes        FORM type ILBM
  1748. X *                BMHD
  1749. X *                CMAP (optional)
  1750. X *                BODY (uncompressed)
  1751. X *
  1752. X ****************************************************************/
  1753. X
  1754. Xwrite_iff (image, wfile)
  1755. XFBM *image;
  1756. XFILE *wfile;
  1757. X{ BitMapHeader bmhd;
  1758. X  unsigned char *cmap, *body;
  1759. X  int bodylen, cmaplen, bmhdlen, formlen, ilbmbits;
  1760. X
  1761. X  if (image->hdr.planes > 1)
  1762. X  { fprintf (stderr, "Error, write_iff cannot handle multi-plane images\n");
  1763. X    return (0);
  1764. X  }
  1765. X
  1766. X  /* Determine number of bits in output */
  1767. X  if (image->hdr.clrlen == 0)
  1768. X  { ilbmbits = image->hdr.bits; }
  1769. X  else
  1770. X  { int colors = image->hdr.clrlen/3;
  1771. X    for (ilbmbits=1; colors > 2; ilbmbits++, colors >>= 1) ;
  1772. X  }
  1773. X  
  1774. X  fprintf (stderr, "Writing \"%s\" [%dx%d] as a %d bit IFF ILBM file\n",
  1775. X       image->hdr.title[0] ? image->hdr.title : "",
  1776. X       image->hdr.cols, image->hdr.rows, ilbmbits);
  1777. X
  1778. X  if (ilbmbits > 5)
  1779. X  { fprintf (stderr, "%s\n%s\n%s\n",
  1780. X    "Warning: most IFF ILBM displays cannot handle more than",
  1781. X    "     32 colors. You should probably run the image though",
  1782. X    "     'gray2clr -u | fbquant -c32' first.");
  1783. X  }
  1784. X
  1785. X  /* Build BMHD, CMAP, and body chunks */
  1786. X  bmhdlen = build_bmhd (image, &bmhd, ilbmbits) ;
  1787. X  cmaplen = build_cmap (image, &cmap, ilbmbits);
  1788. X  bodylen = build_body (image, &body, ilbmbits);
  1789. X  
  1790. X  /* Length of FORM is length of subparts plus 8 for header + 4 for type */
  1791. X  formlen = bmhdlen + cmaplen + bodylen + 12;
  1792. X
  1793. X  /*--------Write out FORM chunk header--------*/
  1794. X  fprintf (wfile, "FORM");
  1795. X  put_long (formlen-8, wfile, BIG);
  1796. X  fprintf (wfile, "ILBM");
  1797. X
  1798. X  /*----Write out BMHD chunk----*/
  1799. X  fprintf (wfile, "BMHD");
  1800. X  put_long (bmhdlen-8, wfile, BIG);
  1801. X  fwrite (&bmhd, bmhdlen-8, 1, wfile);
  1802. X
  1803. X  /* No need to pad BMHD chunk, it must be even */
  1804. X      
  1805. X  /*----Write out CMAP chunk----*/
  1806. X  if (cmaplen > 0)
  1807. X  { fprintf (wfile, "CMAP");
  1808. X    put_long (cmaplen-8, wfile, BIG);
  1809. X    fwrite (cmap, cmaplen-8, 1, wfile);
  1810. X  
  1811. X    /* Pad CMAP chunk if necessary */
  1812. X    if (cmaplen & 1) fputc (0, wfile);
  1813. X  }
  1814. X      
  1815. X  /*----Write out BODY chunk----*/
  1816. X  fprintf (wfile, "BODY");
  1817. X  put_long (bodylen-8, wfile, BIG);
  1818. X  fwrite (body, bodylen-8, 1, wfile);
  1819. X
  1820. X  /* Pad BODY chunk if necessary */
  1821. X  if (bodylen & 1) fputc (0, wfile);
  1822. X      
  1823. X  /*--------Free memory and return--------*/
  1824. X  if (cmap)    free (cmap);
  1825. X  if (body)    free (body);
  1826. X
  1827. X  return (1);
  1828. X}
  1829. X
  1830. X/****************************************************************
  1831. X * build_bmhd: Build a BitMapHeader, and byte swap it if necessary
  1832. X ****************************************************************/
  1833. X
  1834. Xbuild_bmhd (image, bmh, bits)
  1835. XFBM *image;
  1836. XBitMapHeader *bmh;
  1837. Xint bits;
  1838. X{
  1839. X  bmh->w = image->hdr.cols;
  1840. X  bmh->h = image->hdr.rows;
  1841. X  bmh->x = 0;
  1842. X  bmh->y = 0;
  1843. X  bmh->nPlanes = bits;
  1844. X  bmh->masking = 0;  
  1845. X  bmh->compression = 0;
  1846. X  bmh->pad1 = 0;
  1847. X  bmh->transparentColor = 0;
  1848. X  bmh->xAspect = 100;
  1849. X  bmh->yAspect = (image->hdr.aspect * 100.0) + 0.5;
  1850. X  bmh->pageWidth = bmh->w;
  1851. X  bmh->pageHeight = bmh->h;
  1852. X
  1853. X  /* IFF uses BIG byte order, swap if necessary */
  1854. X  if (machine_byte_order () == LITTLE)
  1855. X  { bmh->w = swapword (bmh->w);
  1856. X    bmh->h = swapword (bmh->h);
  1857. X    bmh->x = swapword (bmh->x);
  1858. X    bmh->y = swapword (bmh->y);
  1859. X    bmh->transparentColor = swapword (bmh->transparentColor);
  1860. X    bmh->pageWidth = swapword (bmh->pageWidth);
  1861. X    bmh->pageHeight = swapword (bmh->pageHeight);
  1862. X  }
  1863. X
  1864. X  return (sizeof (*bmh) + 8);
  1865. X}
  1866. X
  1867. X/****************************************************************
  1868. X * build_cmap: Convert an FBM format colormap to IFF format
  1869. X ****************************************************************/
  1870. X
  1871. Xbuild_cmap (image, cmap, bits)
  1872. XFBM *image;
  1873. Xunsigned char **cmap;
  1874. Xint bits;
  1875. X{ register int len, i;
  1876. X  register unsigned char *r, *g, *b, *c;
  1877. X  int colors;
  1878. X
  1879. X  colors = image->hdr.clrlen / 3;
  1880. X  
  1881. X  r = image->cm;
  1882. X  g = r + colors;
  1883. X  b = g + colors;
  1884. X  
  1885. X  len = 3*colors;
  1886. X  *cmap = (unsigned char *) malloc (len);
  1887. X
  1888. X  /* Now convert from three vectors to a vector of triples */
  1889. X  for (i=0, c= *cmap; i<colors; i++)
  1890. X  { *c++ = *r++;
  1891. X    *c++ = *g++;
  1892. X    *c++ = *b++;
  1893. X  }
  1894. X  
  1895. X  /* Return length of chunk, just length of map plus 8 bytes chunk header */
  1896. X  return (len + 8);
  1897. X}
  1898. X
  1899. X/****************************************************************
  1900. X * build_body: Interleave the bits for the byte plane
  1901. X ****************************************************************/
  1902. X
  1903. Xbuild_body (image, body, bits)
  1904. Xregister FBM *image;
  1905. Xunsigned char **body;
  1906. Xint bits;
  1907. X{ int bpr, size;
  1908. X  register unsigned char *obm, *bmp;
  1909. X  register int r, c, k, mask, byte, bit;
  1910. X
  1911. X  bpr = RowBytes (image->hdr.cols);
  1912. X  
  1913. X  size = bpr * image->hdr.rows * bits;
  1914. X  
  1915. X  *body = (unsigned char *) malloc (size);
  1916. X
  1917. X  obm = *body;  
  1918. X
  1919. X  for (r=0; r < image->hdr.rows; r++)
  1920. X  { for (k=0; k<bits; k++)
  1921. X    { mask = 1 << k;
  1922. X      bmp = &(image->bm[r * image->hdr.rowlen]);
  1923. X
  1924. X# ifdef DEBUG      
  1925. X      if (r==23)
  1926. X      { fprintf (stderr, "Row %d, plane %d, bytes: ", r, k);
  1927. X        for (c=0; c<32; c++) fprintf (stderr, "%02x", bmp[c]);
  1928. X    fprintf (stderr, "\n");
  1929. X      }
  1930. X# endif
  1931. X      
  1932. X      for (c=0, byte=0; c<image->hdr.cols; c++)
  1933. X      { bit = (*bmp++ & mask) ? 1 : 0;
  1934. X
  1935. X
  1936. X# ifdef DEBUG
  1937. X        if (r == 23 && c < 32)
  1938. X    { fprintf (stderr, "%d", bit); }
  1939. X# endif
  1940. X
  1941. X    byte = (byte << 1) | bit;
  1942. X        if ((c&7) == 7)
  1943. X    { *obm++ = byte;
  1944. X
  1945. X# ifdef DEBUG
  1946. X      if (r == 23 && c <32) fprintf (stderr, " %d ", byte);
  1947. X# endif
  1948. X
  1949. X      byte=0;
  1950. X        }
  1951. X      }
  1952. X      
  1953. X# ifdef DEBUG
  1954. X      if (r == 23) fprintf (stderr, "\n");
  1955. X# endif
  1956. X      
  1957. X      if ((c & 7) != 0)
  1958. X      { while ((c&7) != 0)
  1959. X        { c++; byte <<= 1; }
  1960. X    *obm++ = byte;
  1961. X      }
  1962. X    }
  1963. X  }
  1964. X  
  1965. X  return (size + 8);
  1966. X  
  1967. X}
  1968. END_OF_FILE
  1969. if test 23454 -ne `wc -c <'fliff.c'`; then
  1970.     echo shar: \"'fliff.c'\" unpacked with wrong size!
  1971. fi
  1972. # end of 'fliff.c'
  1973. fi
  1974. echo shar: End of archive 7 \(of 8\).
  1975. cp /dev/null ark7isdone
  1976. MISSING=""
  1977. for I in 1 2 3 4 5 6 7 8 ; do
  1978.     if test ! -f ark${I}isdone ; then
  1979.     MISSING="${MISSING} ${I}"
  1980.     fi
  1981. done
  1982. if test "${MISSING}" = "" ; then
  1983.     echo You have unpacked all 8 archives.
  1984.     rm -f ark[1-9]isdone
  1985. else
  1986.     echo You still need to unpack the following archives:
  1987.     echo "        " ${MISSING}
  1988. fi
  1989. ##  End of shell archive.
  1990. exit 0
  1991.